/**
 * 对象操作
 */

import {isArray, isFunction, isObject, isString} from "./TypeUtil";
import {log} from "./AppUtil";
import {formatLocaleStr, formatStr} from "./StringUtil";

/**
 * 比较两个对象值是否一致
 * @param objA 比较的对象
 * @param objB 比较的对象
 * @param level 比较层级 默认 -1 无限层级（请不要对比有循环引用的对象 会死循环）
 *                              从1开始 1为往对象内部再比对一层
 * @returns {*}
 */
// @ts-ignore
const objContrast: Function = (objA: any, objB: any, level: number = -1): boolean => {
    if (objA !== objB) {
        // 如果已经是第0层 不完全一致不再往下比对 直接返回false
        if (!level) {
            return false;
        }
        if (!objA !== !objB) {
            return false;
        }
        // 基础类型直接返回false
        if (!isObject(objA)) {
            return false;
        }
        if (typeof (objA) !== typeof (objB)) {
            return false;
        }
        let aKeys = Object.keys(objA);
        // 数组对象keys返回的是迭代器，无法获取length，和Object区分判断
        if (isArray(objA)) {
            if (objA.length !== objB.length) {
                return false;
            }
        } else {
            if (aKeys.length !== Object.keys(objB).length) {
                return false;
            }
        }
        let nextLevel = level === -1 ? level : level - 1;
        for (let key of aKeys) {
            if (!objContrast(objA[key], objB[key], nextLevel)) {
                return false;
            }
        }
    }
    return true;
};

/**
 * 比较两个数组值是否一致
 * @param arrA 比较的数组A
 * @param arrB 比较的数组A
 * @param keyA 数组A唯一keyA
 * @param keyB 数组B唯一keyB
 *
 * @returns {
 *     addArr:[]
 *     updateArr:[]
 *     deleteArr:[]
 * }
 */
// @ts-ignore
const arrContrast: Function = (arrA: any[], arrB: any[], keyA: string = "id", keyB: string = "id"): any => {
    let obj: any = {
        isEqual: true,
        addArr: [],
        updateArr: [],
        deleteArr: []
    };
    arrA = [...arrA];
    arrB = [...arrB];
    arrA.forEach((item: any) => {
        let node: any = arrB.find((i: any) => (i[keyB] === item[keyA]));
        if (node) {
            if (JSON.stringify(node) !== JSON.stringify(item)) {
                obj.updateArr.push(item);
            }
        } else {
            obj.addArr.push(item);
        }
    });
    obj.deleteArr = arrB.filter((i: any) => (arrA.findIndex((k: any) => (k[keyA] === i[keyB])) === -1));
    if (obj.addArr.length || obj.updateArr.length || obj.deleteArr.length) {
        obj.isEqual = false;
    }
    return obj;
}

// @ts-ignore
const objAssign: Function = (...objects) => {
    let result = {};
    for (let obj of objects) {
        if (!obj || !isObject(obj)) continue; // 如果当前值不是对象类型，则跳过
        for (let key in obj) {
            if (isObject(obj[key])) {
                // 如果属性值也是对象且非数组，则递归调用 objAssign 函数进行合并
                result[key] = objAssign((result[key] || {}), obj[key]);
            } else {
                // 否则直接将属性复制到结果对象上
                result[key] = obj[key];
            }
        }
    }
    return result;
}

/**
 * 解析JSON字符串，返回对象
 * @param str
 * @param nullResult  出错的返回值   默认为{}
 * @returns {*}
 */
// @ts-ignore
const strToObject: Function = (str: string, nullResult: object = {}): object => {
    try {
        //eslint-disable-next-line
        let res: any = str ? eval(`(${str})`) : nullResult
        return isObject(res) ? res : nullResult;
    } catch (e) {
        log("转换出错", str);
        return nullResult;
    }
};

// {$not: {typeId: "2005000000IDRECOB211"}}

const typeMap: any = {
    $and: (a: any, b: any) => {
        return a && b;
    },
    $not: (a: any, b: any) => {
        return a && !b;
    },
    $or: (a: any, b: any) => {
        return a || b;
    }
};
/**
 * 根据conObj对象比较obj中的值 返回true或false
 * @param obj 对象
 * @param conObj {K: 比较值} 判断obj中对应k和conObj中的值是否一致
 * @param type $and, $not, $or
 * @returns {boolean}
 */
// @ts-ignore
const objCondition: Function = (obj: any, conObj: any, type: string = "$and"): boolean => {
    let result = true,
        curTypeFn = typeMap[type];
    for (let k in conObj) {
        if (typeMap[k]) {
            result = curTypeFn(result, objCondition(obj, conObj[k], k));
        } else {
            result = curTypeFn(result, obj[k] === conObj[k]);
        }
    }
    return result;
};


/**
 * 根据规则生成对象
 * @param obj 源对象
 * @param rule 规则对象 {新属性名: "源对象属性名"}
 * @param keepOtherAttr 默认false 保留其他属性
 * @param isFormatChild 是否进行深层次取值
 */
// @ts-ignore
const getObjByRule: Function = (obj: any, rule: any, keepOtherAttr: boolean = false, isFormatChild: boolean = false): object => {
    let result = keepOtherAttr ? {...obj} : {};
    for (let k in rule) {
        if (isString(rule[k]) && rule[k].indexOf("$") !== -1) {
            result[k] = formatStr(rule[k], obj);
        } else if (isString(rule[k]) && rule[k].indexOf("|") !== -1) {
            result[k] = formatLocaleStr(rule[k], obj);
        } else if (isFormatChild && isObject(rule[k])) {
            result[k] = getObjByRule(obj, rule[k], keepOtherAttr, isFormatChild);
        } else {
            result[k] = obj[rule[k]] !== undefined ? obj[rule[k]] : rule[k];
        }
    }
    return result;
};

/**
 * 去重id
 * @param {*} arr
 * @returns
 */
export function getRepeat(arr: any[]) {
    let result: any[] = [], resultObj: any = {};
    arr.forEach((item: any) => {
        if (!resultObj[item.id] && item.name) {
            result.push(item);
            resultObj[item.id] = item.id
        }
    });
    return result;
}

/**
 * 按照属性名获取属性值，中途遇到方法会直接调用方法, 如最后一个是方法则会直接返回 属性名支持 . 分割
 * @param obj 对象
 * @param field 属性名  如  type.name
 * @returns {*}
 */
// @ts-ignore
const getObjAttrFun: Function = (obj: any, field: string): any => {
    const _get = (current: any, pathSegments: string[]): any => {
        if (pathSegments.length === 0 || current == null) {
            return current;
        }
        const [firstSegment, ...restSegments] = pathSegments;
        let nextValue: any;
        if (isFunction(current) && restSegments.length > 0) {
            nextValue = current();
        } else {
            nextValue = formatLocaleStr(firstSegment, current);
        }
        if (isArray(nextValue) && restSegments.length > 0) {
            return nextValue.map(item => _get(item, restSegments)).filter(i => i).join(",");
        } else {
            return _get(nextValue, restSegments);
        }
    };
    try {
        const pathSegments = field.split('.');
        return _get(obj, pathSegments);
    } catch (e) {
        return "${" + field + "}";
    }
};


/**
 * 按照属性名获取属性值
 * @param obj 对象
 * @param field 属性名  如  type.name
 * @returns {*}
 */
// @ts-ignore
const getObjAttr: Function = (obj: any, field: string): any => {
    return [obj, ...field.split("\.")].reduce((obj: any, item: string) => {
        let value: any = obj[item];
        return value;
    });
};

export {
    objContrast,
    arrContrast,
    objAssign,
    strToObject,
    objCondition,
    getObjByRule,
    getObjAttrFun,
    getObjAttr
};

